#!/usr/bin/env python
# -*- coding: utf-8 -*-

import sys
import tornado.escape
import tornado.ioloop
import tornado.options
import tornado.web
import tornado.websocket
from config import etc
import Queue
from controls import data_sight_comment_mongo
import json
from utils import log
import threading

from tornado.options import define, options
#define("port", default=8888, help="run on the given port", type=int)

class Application(tornado.web.Application):
    def __init__(self):
        handlers = [
            (r"/websocket", SightCommentSocketHandler),
        ]
        settings = dict(
            template_path = etc.path_template,
            static_path = etc.path_static,
            cookie_secret = etc.cookie_secret,
            xsrf_cookies=True,
        )
        tornado.web.Application.__init__(self, handlers, **settings)

#
comment_upd_que=Queue.Queue(1000)
#comment_upd_que.put({'cityid':99, 'sightid':1})

# key : cityid_sightid, value : user's set()
sight_user_dict={}
# key : user, value : cityid_sightid
user_sight_dict={}

class SightCommentSocketHandler(tornado.websocket.WebSocketHandler):

    def allow_draft76(self):
        # for iOS 5.0 Safari
        return True

    def open(self):
        #print "client is opening :"
        cityid = self.get_argument( 'cityid' )
        sightid = self.get_argument( 'sightid' )
        key = str(cityid) + '_' + str(sightid)
        log.i( "a new client opened, cityid and sightid is :" + key )
        if not cityid or not sightid :
            log.w ( "this websocket will be ingored. cityid or sightid is empty: " + key )
            return None
        if key not in sight_user_dict :
            users = set()
            sight_user_dict[key] = users
        # add user to dict
        users = sight_user_dict[key]
        users.add(self)
        user_sight_dict[self] = key


    def on_close(self):
        log.i( "client is closing" )
        if self in user_sight_dict :
            cityid_sightid = user_sight_dict[self]
            del user_sight_dict[self]
            if cityid_sightid in sight_user_dict :
                sight_user_dict[cityid_sightid].remove(self)

    
    def on_message(self, message=None) :
        log.i( "get a message from client : " + message )
        if not message :
            return None
        # unicode to str
        datastr = message.encode('utf-8')
        data_list = str(datastr).strip().split('_')
        cityid_str = ''
        sightid_str = ''
        if len(data_list) >= 2: 
            cityid_str = data_list[0].strip()
            sightid_str = data_list[1].strip()

        if not cityid_str or not sightid_str :
            log.w( "cityid or sightid is empty: " + message )
            return None
        key = cityid_str + '_' + sightid_str
        if self in user_sight_dict :
            cityid_sightid = user_sight_dict[self]
            if cityid_sightid != key :
                if cityid_sightid in sight_user_dict :
                    sight_user_dict[cityid_sightid].remove(self)

        if key not in sight_user_dict :
            users = set()
            sight_user_dict[key] = users
        # add user to dict
        users = sight_user_dict[key]
        users.add(self)
        user_sight_dict[self] = key

        comment = data_sight_comment_mongo.get_sight_comment(int(cityid_str), int(sightid_str))
        res = json.dumps(comment)
        self.write_message(res)

        log.i( "on_message send msg to client : " + message )

# when someone add a comment for a sight, push data to users which is looking this sight
class ProcessTh(threading.Thread):
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.t_name = name
 
    def run(self):
        city_sight = None
        #time.sleep(10)
        while True :
            try :
               # block method
               city_sight = comment_upd_que.get()
               comment = data_sight_comment_mongo.get_sight_comment(int(city_sight['cityid']), int(city_sight['sightid']))
               res = json.dumps(comment)

               key = str(city_sight['cityid']) + '_' + str(city_sight['sightid'])
               # no one is looking this sight
               if key not in sight_user_dict :
                   continue
               all_user = sight_user_dict[key]
               log.i( "sending message to %d waiters", len(all_user) )
               for user in all_user :
                   user.write_message(res)
            except Exception as e :
                log.exp(e)

def main( p_port ) :
    if p_port == 0 :
        print 'websocket port could not be set as 0'
        log.e( 'websocket port could not be set as 0' )
        exit( 1 )
    log.c( 'websocket listening on port : %s' % p_port )
    tornado.options.parse_command_line()
    app = Application()
    app.listen( p_port )
    tornado.ioloop.IOLoop.instance().start()
'''
def main():
    tornado.options.parse_command_line()
    app = Application()
    app.listen(8880)
    tornado.ioloop.IOLoop.instance().start()
'''

port = 0
try :
    port = int( sys.argv[1].split('=')[1] )
except :
    print 'need port params'
    log.e( 'need port params' )
    exit( 1 )

if __name__ == "__main__":
    push_comment = ProcessTh("push comment")
    #push_comment.setDaemon(True)
    push_comment.start()
    main(port)